package FALCON;

import Bots.Buffer;

import java.io.*;
import java.util.Random;

public class FALCON {
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 超参
    public double[] alpha = new double[]{0.1, 0.1, 0.1}; // 激活偏移率
    public double[] gamma = new double[]{0.5, 0.5, 0}; // 激活(贡献)率

    public static double QEpsilonDecay = 0.05;    // 探索率衰减
    public static double QEpsilon = 0.75;       // 探索率

    public int access = 1;                                   // 不同激活算法

    public double[] beta = new double[]{1.0, 1.0, 1.0};           // 学习率

    public double epilson = 0.001;                     // 没用
    public double[] rho = new double[]{0.2, 0.2, 0.5}; // 匹配（警戒）率


    public double QAlpha = 0.5;                    // Q学习率
    public double QGamma = 0.1;                    // 折扣率
    final boolean Bound = false;                            // 有限制的

    final double eta = 0.1;                                    // 变异率
    final double veta = 0.1;                                   // 变异机率
    public boolean is_mutated = false;                        // 是否变异
    final int seed = 50;                                        // 随机种子


    //构造
    final int capacity = 19999;                                                 // 容量
    final int WriteInTarget = 50;                                               //
    static int K = 16;                                                           //

    public int numState;                                                   // 状态数量
    public int numAction;                                                  // 动作数量
    public int numReward = 2;                                                // 奖励数量

    public final int numSpace = 3;                                           // 空间
    public final int CURSTATE = 0;                                           // 状态
    public final int ACTION = 1;                                           // 动作
    public final int REWARD = 2;                                           // 奖励

    public double[][] I;                                                       // 输入域

    public double[] T;                                                       // (每个节点的)激活值
    public int[] numInput;                                                // 输入

    public int numCode = 0;                                               //
    public double[][][] W;                                                     // 网络内部权重参数
    public int[] N;                                                           //


    public double[][][] target_W;                                              // 目标网络权重


    public boolean[] newCode;                                                  // 判断是否为新结点

    public int use_buff = 0;                                                       // 是否使用buff
    public int view = 2;                                                           // 没用
    static Random ran;                                                           // 随机值

    public FALCON(int agent_num, int numState, int numAction, boolean rw, String name) {
        ran = new Random();
        ran.setSeed(seed);

        this.numState = numState;                                                  // 状态数
        this.numAction = numAction;                                                // 动作数

        numInput = new int[numSpace];   //// numSpace:0-State 1-Action 2-Reward 
        numInput[0] = numState;                                                  // 
        numInput[1] = numAction;                                                 // 
        numInput[2] = numReward;                                                 //

        I = new double[numSpace][];
        for (int i = 0; i < numSpace; i++)
            I[i] = new double[numInput[i]];                                      // 实体化对象


        T = new double[capacity];
        N = new int[capacity];

        if (!rw) {
            numCode = 0;
            newCode = new boolean[capacity];
            newCode[numCode] = true;
            N[numCode] = 0;
            W = new double[capacity][][];
            target_W = new double[capacity][][];
            for (int j = 0; j < numCode + 1; j++) {
                W[j] = new double[numSpace][];
                target_W[j] = new double[numSpace][];
                for (int k = 0; k < numSpace; k++) {
                    W[j][k] = new double[numInput[k]];
                    target_W[j][k] = new double[numInput[k]];
                    for (int i = 0; i < numInput[k]; i++) {
                        W[j][k][i] = 1.0;                             // 实体化对象
                        target_W[j][k][i] = 1.0;
                    }
                }
            }
        } else {
            try {
                readfile(agent_num, name);                                     // 读取智能体的本地权重数据
            } catch (Exception e) {
                System.out.println("error");
                numCode = 0;
                newCode = new boolean[capacity];                             // 结点提前空出空间

                newCode[0] = true;
                N[0] = 0;

                T = new double[capacity];                                    // 激活值提前空出空间

                W = new double[capacity][][];                                // 网络权重
                target_W = new double[capacity][][];

                for (int j = 0; j < numCode + 1; j++) {
                    W[j] = new double[numSpace][];                          //
                    target_W[j] = new double[numSpace][];
                    for (int k = 0; k < numSpace; k++) {
                        W[j][k] = new double[numInput[k]];                  //
                        target_W[j][k] = new double[numInput[k]];
                        for (int i = 0; i < numInput[k]; i++) {
                            W[j][k][i] = 1.0;                       //
                            target_W[j][k][i] = 1.0;
                        }
                    }
                }
            }
            System.out.println("numCode");
            System.out.println(numCode);
        }
    }


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    //提取环境信息
    public void setState(double[] stat) {//提取状态
        //stat[i]=(((int)(stat[i]*100.0))/100.0);
        if (numState >= 0) System.arraycopy(stat, 0, I[CURSTATE], 0, numState);
    }


    public void setAction(double[] act) {//提取动作
        if (numAction >= 0) System.arraycopy(act, 0, I[ACTION], 0, numAction);
    }

    public void setAction(int action) {//提取动作
        for (int i = 0; i < numAction; i++)
            I[ACTION][i] = 0;
        I[ACTION][action] = 1;
    }

    public void setReward(double r) {//提取奖励
        if (r > 1) r = 1;
        if (r < 0) r = 0;
        I[REWARD][0] = r;
        I[REWARD][1] = 1 - r;
    }


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


    //表现部分

    public void Nx(int num, double[] x) {  // 没用上
        double sum = 0.0;
        for (int i = 0; i < num; i++) {
            sum += Math.pow(x[i], 2);
        }
        sum = Math.pow(sum, 1.0 / 2.0); // 计算欧式距离
        for (int i = 0; i < num; i++) {
            x[i] = x[i] / sum;         // 利用欧式距离正则化向量
        }
    }

    public double distance(int num, double[] x) {  // 计算欧式距离(向量模)
        double sum = 0.0;
        for (int i = 0; i < num; i++) {
            sum += Math.pow(x[i], 2);                //
        }
        sum = Math.pow(sum, 1.0 / 2.0);
        return sum;
    }


    //代码激活（F2节点思考T--activityF2）


    int learn_func = 3;

    public boolean is_teacher = false;

    public void CodeActivition(int numSpace) {

        //if(access == 0) {
        //4.comvinatorial operations
        double top, bottom;
        for (int j = 0; j < numCode + 1; j++) {   // 各类激活函数
            T[j] = 0;
            int k;
            for (k = 0; k < REWARD; k++) {                        // 这段代码是模糊计算
                top = 0;                                      // 顶部
                bottom = alpha[k];                    // 底部增加参数解决为0时的过大值问题
                for (int i = 0; i < numInput[k]; i++) {           // (I v W) / W
                    top += Math.min(I[k][i], W[j][k][i]);     // 一种模糊技术,扩大记忆量,会小于W
                    bottom += W[j][k][i];                     // W
                }
                T[j] += gamma[k] * (top / bottom);        // Tj
            }

            k = REWARD;
            top = 0;
            bottom = 0;
            for (int i = 0; i < numInput[k]; i++) { //(I v W) / W
                top += I[k][i] * W[j][k][i];      // I * W 会小于 W
            }
            bottom = distance(numInput[k], I[k]) * distance(numInput[k], W[j][k]);   // 计算欧式距离
            T[j] += gamma[k] * (top / bottom); //Tj
        }
        //}
    	
    	/*
    	if(access == 1) {
    		double top, bottom;
            for (int j=0; j<numCode+1; j++) {              // 激活函数
                T[j]=0;                                    // 激活值初始化
                int k=0;                                   // 
                for (k=0; k<numSpace; k++) {               // 遍历所有空间
                    top = 0;                               // 
                    bottom = alpha[k];             //
                    for (int i=0; i<numInput[k]; i++) { //(I v W) / W
                    	top += Math.min (I[k][i],W[j][k][i]); 
                    	bottom += W[j][k][i];
                    }
                    T[j] += gamma[k]*(top/bottom); // Tj
                }
            }
        }
        */
    }


    //代码竞争（判断最好的思考）

    public int CodeCompetition() {
        int J = 0;
        double max_act = Double.MIN_VALUE;         //
        for (int j = 0; j < numCode + 1; j++)
            if (T[j] > max_act) {                           // 找出最大的激活函数
                max_act = T[j];
                J = j;
            }
        return J;
    }


    //活动读出（提取记忆）
    public void WtoI(int J) {
        // 从权重参数W提取到输入域来使用
        if (numInput[REWARD] >= 0) System.arraycopy(W[J][REWARD], 0, I[REWARD], 0, numInput[REWARD]);

    }

    public double Q_Function(double[] stat, int action) {
        double QValue;
        setState(stat);                 // 将状态提取到输入空间中
        setAction(action);              // 将动作输入到输入空间中
        CodeActivition(2);                // 代码激活（每个节点思考）
        int J = CodeCompetition();       // 选最大的(最好的)

        ///////////////////////
        //本身论文没有代码带的（测试试试）
        /*
        boolean reset=true,
        perfectMismatch=false;
        while (reset && !perfectMismatch) { 		   // 第一次必执行   
                reset = false;
                for (int k = 0; k < numSpace; k++ ) {
                    match[k] = TemplateMatching(k,J);    // 模板匹配（判断我们的数据偏差是否过于大）
        		}
                if (match[CURSTATE]<rho[CURSTATE]||match[ACTION]<rho[ACTION]||match[REWARD]<rho[REWARD]) {//如果相似度过低
                    if (match[CURSTATE]==1) {      // 状态相似度完全相同
                        perfectMismatch=true;      // 那估计现如今环境发生重大变化，直接写入新数据
                        doOverwrite (J);
                    }else {//相似度低就重新初始化并更新阈值函数并重新选择
                    T[J] = 0;  // 相似度过低就不用他来激活
                    J=CodeCompetition ();      // 代码竞争（判断最好的思考）
                    reset = true;              
                   }
               }   
         }
         */
        ///////////////////////////////
        //从记忆中提取Q值
        WtoI(J);                       // F1节点提取记忆（Q值）
        if (I[REWARD][0] == I[REWARD][1] && I[REWARD][0] == 1) { //初次记忆
            QValue = 0.5;    // 没记忆就初始化为0.5
        } else
            QValue = I[REWARD][0];  // 有记忆就用记忆
        //if(is_mutated)QValue=mutated_QValue_Update(QValue);
        return (QValue);
    }

    public double Q_Function(double[] stat, boolean[] vact) {
        double[] qValues = new double[numAction];
        double maxQ = Double.MIN_VALUE;
        if (access == 0) {               // access
            setState(stat);
            for (int i = 0; i < numAction; i++) {  // 设置动作,掩码
                if (vact[i]) {     // 如果可以使用就1,不行就0
                    I[ACTION][i] = 1;   //
                } else {
                    I[ACTION][i] = 0;   //
                }
            }
            setReward(1);               // 设置奖励为1
            CodeActivition(3);            // 代码激活（每个节点思考）
            int J = CodeCompetition();   //
            WtoI(J);                   //
            if (I[REWARD][0] == I[REWARD][1] && I[REWARD][0] == 1) {
                maxQ = 0.5;      //
            } else {
                maxQ = I[REWARD][0];
            }
        }
        if (access == 1) {
            for (int action = 0; action < numAction; action++) {   //每个动作试了
                if (vact[action]) {
                    qValues[action] = Q_Function(stat, action);   // 估计当前状态下所有的行为Q值
                } else {
                    qValues[action] = 0;
                }
                if (qValues[action] > maxQ) {
                    maxQ = qValues[action];
                }
            }
        }
        return maxQ;
    }

    public int J_Function(double[] stat, int action) {  // 关注是哪个代码激活了
        setState(stat);             // 设置状态
        setAction(action);          // 设置动作
        CodeActivition(2);            // 代码激活（每个节点思考）
        return CodeCompetition(); //
    }

    public int maxQ0 = 0;
    public int maxQ1 = 0;
    public int maxQ2 = 0;
    public int maxQ3 = 0;
    public int maxQ4 = 0;
    public int maxQ5 = 0;
    public int maxQ6 = 0;
    public int maxQ7 = 0;
    public int maxQ8 = 0;
    public int maxQ9 = 0;

    public int minQ0 = 0;
    public int minQ1 = 0;
    public int minQ2 = 0;
    public int minQ3 = 0;
    public int minQ4 = 0;
    public int minQ5 = 0;
    public int minQ6 = 0;
    public int minQ7 = 0;
    public int minQ8 = 0;
    public int minQ9 = 0;

    public int mmQ0 = 0;
    public int mmQ1 = 0;
    public int mmQ2 = 0;
    public int mmQ3 = 0;
    public int mmQ4 = 0;
    public int mmQ5 = 0;
    public int mmQ6 = 0;
    public int mmQ7 = 0;
    public int mmQ8 = 0;
    public int mmQ9 = 0;

    public double I_Function(double[] stat, boolean[] vact) {
        double[] qValues = new double[numAction];
        double maxQ = Double.MIN_VALUE;
        double minQ = Double.MAX_VALUE;
        if (access == 0) {
            for (int i = 0; i < numAction; i++) {
                if (vact[i]) {
                    I[ACTION][i] = 1;
                } else {
                    I[ACTION][i] = 0;
                }
            }
            setState(stat);
            setReward(1);
            CodeActivition(3);            //代码激活（每个节点思考）
            int J = CodeCompetition();
            WtoI(J);
            if (I[REWARD][0] == I[REWARD][1] && I[REWARD][0] == 1) {
                maxQ = 0.5;
            } else {
                maxQ = I[REWARD][0];
            }

            setState(stat);
            setReward(0);
            CodeActivition(3);            //代码激活（每个节点思考）
            J = CodeCompetition();
            WtoI(J);
            if (I[REWARD][0] == I[REWARD][1] && I[REWARD][0] == 1) {
                minQ = 0.5;
            } else {
                minQ = I[REWARD][0];
            }
        }
        if (access == 1) {
            for (int action = 0; action < numAction; action++) {
                qValues[action] = Q_Function(stat, action);   //估计当前状态下所有的行为Q值
                if (qValues[action] > maxQ) {
                    maxQ = qValues[action];   // 选择最大Q
                }
                if (qValues[action] < minQ) {
                    minQ = qValues[action];   // 选择最小Q
                }
            }
        }
        // 一些统计数据
        if (maxQ < 1.0 && maxQ > 0.9) maxQ9++;
        if (maxQ < 0.9 && maxQ > 0.8) maxQ8++;
        if (maxQ < 0.8 && maxQ > 0.7) maxQ7++;
        if (maxQ < 0.7 && maxQ > 0.6) maxQ6++;
        if (maxQ < 0.6 && maxQ > 0.5) maxQ5++;
        if (maxQ < 0.5 && maxQ > 0.4) maxQ4++;
        if (maxQ < 0.4 && maxQ > 0.3) maxQ3++;
        if (maxQ < 0.3 && maxQ > 0.2) maxQ2++;
        if (maxQ < 0.2 && maxQ > 0.1) maxQ1++;
        if (maxQ < 0.1 && maxQ > 0.0) maxQ0++;

        if (minQ < 1.0 && minQ > 0.9) minQ9++;
        if (minQ < 0.9 && minQ > 0.8) minQ8++;
        if (minQ < 0.8 && minQ > 0.7) minQ7++;
        if (minQ < 0.7 && minQ > 0.6) minQ6++;
        if (minQ < 0.6 && minQ > 0.5) minQ5++;
        if (minQ < 0.5 && minQ > 0.4) minQ4++;
        if (minQ < 0.4 && minQ > 0.3) minQ3++;
        if (minQ < 0.3 && minQ > 0.2) minQ2++;
        if (minQ < 0.2 && minQ > 0.1) minQ1++;
        if (minQ < 0.1 && minQ > 0.0) minQ0++;
        double mmQ = maxQ - minQ;

        if (mmQ < 1.0 && mmQ > 0.9) mmQ9++;
        if (mmQ < 0.9 && mmQ > 0.8) mmQ8++;
        if (mmQ < 0.8 && mmQ > 0.7) mmQ7++;
        if (mmQ < 0.7 && mmQ > 0.6) mmQ6++;
        if (mmQ < 0.6 && mmQ > 0.5) mmQ5++;
        if (mmQ < 0.5 && mmQ > 0.4) mmQ4++;
        if (mmQ < 0.4 && mmQ > 0.3) mmQ3++;
        if (mmQ < 0.3 && mmQ > 0.2) mmQ2++;
        if (mmQ < 0.2 && mmQ > 0.1) mmQ1++;
        if (mmQ < 0.1 && mmQ > 0.0) mmQ0++;

        return maxQ - minQ;
    }


    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    public double eval(Buffer buff) { // 以前遗留的，未使用，计算loss
        double y;
        if (buff.end) {
            y = buff.r;
        } else {
            y = MaxQValue(buff.next_stat, buff.r);            // 计算下次状态最大Q值
        }
        double QValue = Q_Function(buff.stat, buff.action); // 计算本状态Q
        return Math.abs(y - QValue);
    }


    //行动策略选择行为


    public int Policy(double[] stat, boolean[] vact) {         // 以前遗留的，现在将策略与规划分开了
        double[] qValues = new double[numAction];              //
        int[] doubleValues = new int[qValues.length];       //
        int selectedAction = -1;                             // 
        double maxQ = Double.MIN_VALUE;                       //
        int maxDV = 0;                                       //

        //策略选择行为
        if (access == 0) {//Direct Access
            if (ran.nextDouble() < QEpsilon) {//随机行为
                do {
                    selectedAction = (int) (Math.random() * numAction);
                } while (!vact[selectedAction]);
            } else {
                for (int i = 0; i < numAction; i++) {
                    if (vact[i]) {
                        I[ACTION][i] = 1;
                    } else {
                        I[ACTION][i] = 0;
                    }
                }
                setState(stat);
                setReward(1);
                CodeActivition(3);            //代码激活（每个节点思考）
                double maxA = Double.MIN_VALUE;
                int J = CodeCompetition();
                for (int action = 0; action < numAction; action++) {
                    I[ACTION][action] = Math.min(I[ACTION][action], W[J][ACTION][action]);
                    if (maxA < I[ACTION][action]) {
                        maxA = I[ACTION][action];
                        selectedAction = action;
                        doubleValues[maxDV] = selectedAction;
                        maxDV = 1;
                    } else if (maxA == I[ACTION][action]) {
                        doubleValues[maxDV] = action;
                        maxDV++;
                    }
                }
                if (maxDV > 1) {   // 如果最好行为重复了，随机选一个
                    int randomIndex = (int) (Math.random() * maxDV);
                    selectedAction = doubleValues[randomIndex];
                }
                WtoI(J);
                if (I[REWARD][0] == I[REWARD][1] && I[REWARD][0] == 1) {
                    maxQ = 0.5;
                } else
                    maxQ = I[REWARD][0];
            }

        } else if (access == 1) {//valliance
            if (Math.random() < QEpsilon) {    //随机行为
                do {
                    selectedAction = (int) (Math.random() * numAction);
                } while (!vact[selectedAction]);
            } else {//选择的行为
                for (int action = 0; action < numAction; action++) {
                    if (vact[action]) {
                        qValues[action] = Q_Function(stat, action);   //估计当前状态下所有的行为Q值
                    } else {
                        qValues[action] = 0;
                    }
                    if (qValues[action] > maxQ) {
                        selectedAction = action;
                        maxQ = qValues[action];
                        doubleValues[maxDV] = selectedAction;
                        maxDV = 1;
                    } else if (qValues[action] == maxQ) {
                        doubleValues[maxDV] = action;
                        maxDV++;
                    }
                }
                if (maxDV > 1) {   // 如果最好行为重复了，随机选一个
                    int randomIndex = (int) (Math.random() * maxDV);
                    selectedAction = doubleValues[randomIndex];
                }

            }
        }
        return selectedAction;
    }


    public boolean is_newCode = false;
    public int num_newCode = 0;

    public int sPolicy(double[] stat, boolean[] vact) {    // 选在使用的，策略和规划分割，只保留策略部分
        double[] qValues = new double[numAction];
        int[] doubleValues = new int[qValues.length];
        int selectedAction = -1;
        double maxQ = Double.MIN_VALUE;
        int maxDV = 0;
        //策略选择行为
        if (access == 0) {                                 // Direct Access
            for (int i = 0; i < numAction; i++) {
                if (vact[i]) {
                    I[ACTION][i] = 1;
                } else {
                    I[ACTION][i] = 0;
                }
            }
            setState(stat);
            setReward(1);
            CodeActivition(3);            //代码激活（每个节点思考）
            double maxA = Double.MIN_VALUE;
            int J = CodeCompetition();
            for (int action = 0; action < numAction; action++) {
                I[ACTION][action] = Math.min(I[ACTION][action], W[J][ACTION][action]);
                if (maxA < I[ACTION][action]) {
                    maxA = I[ACTION][action];
                    selectedAction = action;
                    doubleValues[maxDV] = selectedAction;
                    maxDV = 1;
                } else if (maxA == I[ACTION][action]) {
                    doubleValues[maxDV] = action;
                    maxDV++;
                }
            }
            if (maxDV > 1) {   // 如果最好行为重复了，随机选一个
                int randomIndex = (int) (Math.random() * maxDV);
                selectedAction = doubleValues[randomIndex];
            }
            WtoI(J);
            if (I[REWARD][0] == I[REWARD][1] && I[REWARD][0] == 1) {
                maxQ = 0.5;
                is_newCode = true;
                num_newCode++;
            } else {
                maxQ = I[REWARD][0];
                is_newCode = false;
            }
        } else if (access == 1) {                      // 传统方式
            for (int action = 0; action < numAction; action++) {
                if (vact[action]) {
                    qValues[action] = Q_Function(stat, action);   // 估计当前状态下所有的行为Q值
                    if (is_mutated) qValues[action] = mutated_QValue_Update(qValues[action]);
                } else {
                    qValues[action] = 0;                // 不可用Q值为0
                }
                if (qValues[action] > maxQ) {
                    selectedAction = action;     //
                    maxQ = qValues[action];      // 更新最大Q值
                    doubleValues[maxDV] = selectedAction; //
                    maxDV = 1;                   // 新的则重设为1
                } else if (qValues[action] == maxQ) {// 如果存在相等Q值
                    doubleValues[maxDV] = action; //
                    maxDV++;                      //
                }
            }
            if (maxDV > 1) {                     // 如果最好行为重复了，随机选一个动作
                int randomIndex = (int) (Math.random() * maxDV); //
                selectedAction = doubleValues[randomIndex];     //
            }
            //double []act =new double [numAction];
            //actiontoact(selectedAction,act);
        }
        return selectedAction;
    }


/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


    //学习部分

    //模板匹配（判断是否合理）
    public double TemplateMatching(int k, int j) {
        double m = 0.0;             // 分子
        double denominator = 0.0; // 分母

        for (int i = 0; i < numInput[k]; i++) { // 相似度
            m += Math.min(I[k][i], W[j][k][i]);  // 还是采用模糊算法
            denominator += I[k][i];        // 与激活函数不同，这里采用I，保证新结点一定能兜住
        }
        if (denominator == 0)                 // 不可能发生
            return (0);                     // 
        else
            return (m / denominator);
    }

    //模板学习（更新记忆）

    public void TemplateLearning(int J) {
        if (newCode[J]) {                                        // 如果是新结点
            //combinatorial operations
            int k;                                         //
            for (k = 0; k < REWARD; k++) {                       // 再次记忆
                for (int i = 0; i < numInput[k]; i++) {          //
                    W[J][k][i] = Math.min(W[J][k][i], I[k][i]); // 模糊计算直接覆盖
                }
            }
            k = REWARD;                                        //
            //
            //
            if (numInput[k] >= 0) System.arraycopy(I[k], 0, W[J][k], 0, numInput[k]);
            newCode[J] = false;                                    // 被使用了自然不是新的了
            createNewCode();                                    // 创建一个新的节点
        } else {

            //combinatorial operations
            int k;
            for (k = 0; k < REWARD; k++) {//再次记忆
                for (int i = 0; i < numInput[k]; i++) {
                    W[J][k][i] = (1 - beta[k]) * W[J][k][i] + beta[k] * Math.min(W[J][k][i], I[k][i]); // 慢慢偏向模糊计算结果
                }
            }
            k = REWARD;
            for (int i = 0; i < numInput[k]; i++) {
                W[J][k][i] = (1 - beta[k]) * W[J][k][i] + beta[k] * I[k][i];            // 慢慢偏向I

            }
        }
    }
    //新写入

    public void doOverwrite(int J) {
        // 将I重写
        for (int k = 0; k < numSpace; k++)
            if (numInput[k] >= 0) System.arraycopy(I[k], 0, W[J][k], 0, numInput[k]);
    }

    //创建新节点    
    public void createNewCode() {
        if (numCode < capacity)
            numCode++;                                              // 结点数增加
        newCode[numCode] = true;                                    // 各类初始化，实例化空间
        W[numCode] = new double[numSpace][];                        // 
        for (int k = 0; k < numSpace; k++) {
            W[numCode][k] = new double[numInput[k]];                // 
            for (int i = 0; i < numInput[k]; i++)
                W[numCode][k][i] = 1.0;                     //
        }
    }

    //计算下一状态的softmax Q值
    //softmax Q'(s' , a')= log  [< (e**Q'(s',a') )/N

    public double SoftMaxQValue(double[] next_stat, double r) {  // 以前写的，可能理解存在问题
        double softmax_Q;
        double sum_soft_Q = 0.0;
        for (int action = 0; action < numAction; action++) {//Q-学习
            double tmp_Q = Q_Function(next_stat, action);
            sum_soft_Q += Math.pow(Math.E, tmp_Q);
        }
        sum_soft_Q /= numAction;
        softmax_Q = Math.log(sum_soft_Q);
        return r + QGamma * softmax_Q;
    }

    public double SoftMax(double[] Qvalue) {  // softmax 计算公式，使得结果反应整体水平
        double softmax_Q;
        double max_Q = Double.MIN_VALUE;
        double sum_soft_Q = 0.0;

        for (int i = 0; i < numAction; i++) {//Q-学习
            sum_soft_Q += Math.pow(Math.E, Qvalue[i]);
            if (max_Q < Qvalue[i]) {
                max_Q = Qvalue[i];
            }
        }
        softmax_Q = Math.pow(Math.E, max_Q) / sum_soft_Q;
        return softmax_Q;
    }

    public double SoftMax(double[] Qvalue, double Q) {  // 计算单个的softmax，似乎没啥用
        double softmax_Q;
        double sum_soft_Q = 0.0;

        for (int i = 0; i < numAction; i++) {//Q-学习
            sum_soft_Q += Math.pow(Math.E, Qvalue[i]);
        }
        softmax_Q = Math.pow(Math.E, Q) / sum_soft_Q;
        return softmax_Q;
    }

    public double MaxQValue(double[] next_stat, double r) {   // 最大Q值，实际是求Q值目标
        double max_Q = Double.MIN_VALUE;
        for (int action = 0; action < numAction; action++) {//Q-学习
            double tmp_Q = Q_Function(next_stat, action);      // 下一个状态
            if (max_Q < tmp_Q) {
                max_Q = tmp_Q;
            }
        }
        return r + QGamma * max_Q;                           // 当前奖励 + 下一个状态最好结果
    }

    //Q学习公式

    //Q( s , a ) = Q( s , a )- a(r(s,a) + softmax Q' (s',a') ) )
    public double QValue_Update(double QValue, double y) {
        if (Bound) QValue = QValue - QAlpha * (QValue - y) * (1 - QValue);
        else {
            QValue = QValue - QAlpha * (QValue - y);// 新Q = 旧Q +（奖励 + 新状态最大Q - 旧Q）
            if (QValue < 0) QValue = 0;               // 不希望太大或太小
            if (QValue > 1) QValue = 1;               //
        }
        return QValue;
    }

    public double mutated_QValue_Update(double QValue) {
        return (1 - eta) * QValue + eta * Math.random(); // 对Q值进行变异，幅度在0-0.1之间
    }

    int xx, yy, zz;
    double[] match = new double[numSpace];

    public double loss = 0;


    public void Q_Function_update(Buffer buff) {
        int numSpace = 3;
        double y;
        if (buff.end) {
            y = buff.r;                           // 状态结束了自然没有下一个状态
        } else {
            y = MaxQValue(buff.next_stat, buff.r); // 计算目标值
            //y=SoftMaxQValue(buff.next_stat,buff.r);
        }
        //if (y<0) y = 0;
        //if (y>1) y = 1;
        double QValue = Q_Function(buff.stat, buff.action); // 计算本状态Q

        buff.p = Math.abs(y - QValue);                // 没用的东西
        buff.w = 1;                                 // 没用的东西
        loss += Math.abs(y - QValue);                 // 计算的loss
        QValue = QValue_Update(QValue, y);    // Q学习公式，本质减少loss，计算出新Q值
        //if(is_mutated)QValue=mutated_QValue_Update(QValue);

        //代理读取之前的状态
        setState(buff.stat);            // 设置当前什么状态
        setAction(buff.action);         // 设置做了什么动作
        setReward(QValue);              // 是新Q值
        CodeActivition(3);                // 代码激活（每个节点思考）保证绝对收敛
        int J = CodeCompetition();        // 代码竞争（判断最好的思考）
        do {
            for (int k = 0; k < numSpace; k++) match[k] = TemplateMatching(k, J);    // 模板匹配（判断我们的数据偏差是否过于大）
            if (match[CURSTATE] < rho[CURSTATE] ||
                    match[ACTION] < rho[ACTION] ||
                    match[REWARD] < rho[REWARD]) {//如果相似度过低
                if (match[CURSTATE] == 1) {      // 状态相似度完全相同
                    doOverwrite(J);
                    break;
                } else {//相似度低就重新初始化并更新阈值函数并重新选择
                    T[J] = 0;  // 相似度过低就不用他来激活
                    J = CodeCompetition();      // 代码竞争（判断最好的思考）
                    continue;
                }
            }
            TemplateLearning(J);
        } while (false);
    }


    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    public void readfile(int agent_num, String name) throws IOException {  // 读写文件部分
        String path = "e:/" + name + agent_num + ".txt";
        FileInputStream in = new FileInputStream(path);
        DataInputStream din = new DataInputStream(in);
        numCode = din.readInt();

        newCode = new boolean[capacity];


        T = new double[capacity];

        W = new double[capacity][][];
        target_W = new double[capacity][][];


        for (int j = 0; j < numCode + 1; j++) {

            W[j] = new double[numSpace][];
            newCode[j] = din.readBoolean();
            N[j] = din.readInt();
            for (int k = 0; k < numSpace; k++) {

                W[j][k] = new double[numInput[k]];
                for (int i = 0; i < numInput[k]; i++) {
                    W[j][k][i] = din.readDouble();
                }
            }
        }
        din.close();
        in.close();

    }

    public void writefile(int agent_num, String name) throws Exception {
        String path = "e:/" + name + agent_num + ".txt";
        FileOutputStream out = new FileOutputStream(path);
        DataOutputStream dout = new DataOutputStream(out);

        dout.writeInt(numCode);

        for (int j = 0; j < numCode + 1; j++) {

            dout.writeBoolean(newCode[j]);
            dout.writeInt(N[j]);
            for (int k = 0; k < numSpace; k++) {
                for (int i = 0; i < numInput[k]; i++) {
                    dout.writeDouble(W[j][k][i]);
                }
            }
        }
        dout.close();
        out.close();
    }


}